<h4>Control Keywords</h4>
<dl class="dl-horizontal small">
	<dt>[[LayerChange layer]]</dt>
	<dd>Change current layer <samp>eg. [[LayerChange 22.1]]</samp></dd>
	<dt>[[PositionSet mm]]</dt>
	<dd>Update current absolute position <samp>eg. [[PositionSet 22.1]]</samp></dd>
	<dt>[[PositionChange mm]]</dt>
	<dd>Update relative position update <samp>eg. [[PositionChange -2.1]]</samp></dd>
</dl>
<br>
<h4>Action Keywords</h4>
<dl class="dl-horizontal small">
	<dt>[[DisplayLayer LayerID]]</dt>
	<dd>Display any layer from current plate <samp>eg. [[DisplayLayer 10]]</samp></dd>
	<dt>[[Blank]]</dt>
	<dd>Make screen blank</dd>
	<dt>[[LayerSkip Value]]</dt>
	<dd>For the positive values it skips a layer <samp>eg. [[LayerSkip 1]]</samp><br><br>
		It skips any remaining gcode and layer tasks, and starts the next layer.<br><br>
		The more advanced use case example: <samp>[[LayerSkip ((100>[[TotalSolidArea]])*(1-[[SkippedLayers]])*([[LayerNumber]]>3))]]</samp><br>
		The gcode above would cause layers to be skipped after the first 3 layers if a layer before the current one has not been skipped and the difference between the previous and the current layer is less than 100 pixels.
	</dd>
	<dt>[[Delay Seconds]]</dt>
	<dd>Put delay <samp>eg. [[Delay 1.23]]</samp></dd>
	<dt>[[WaitForDoneMessage]]</dt>
	<dd>Wait for <kbd>Z_move_comp</kbd> message from RAMPS or similar boards</dd>
	<dt>[[WaitForDoneMessage n]]</dt>
	<dd>Wait for <kbd>Z_move_comp</kbd> message from RAMPS or wait for n second. Which happens earlier</dd>
	<dt>[[ResponseCheck ExpectedOK BufferSize]]</dt>
	<dd>Helps syncronize fast moving SLS and laser SLA systems. It limits how many gcode will be send to RAMPS before waiting for response from RAMPS. It requires ok response from RAMPS after commands get completed and not after receiving them.
		<br><kbd>ExpectedOK</kbd> integer indicates how many OK will be received from RAMPS board.
		<br><kbd>BufferSize</kbd> indicates how many command should be sent out before receiving OK responses.		
		<br><samp>eg. [[ResponseCheck 1 3]]</samp></dd>
	<dt>[[Pause]]</dt>
	<dd>Pause the printer, requires resume from dashboard to continue.</dd>
</dl>
<br>
<h4>Communication Keywords</h4>
<dl class="dl-horizontal small">
	<dt>[[Net URL]]</dt>
	<dd>Send get request to the specified URL without waiting for the result <samp>eg. [[Net http://example.com/api]]</samp></dd>
	<dt>[[NetReturn URL]]</dt>
	<dd>Send get request to the specified URL and send the result to RAMPS <samp>eg. [[NetReturn http://127.0.0.1/gcode?layer=[[LayerNumber]]]]</samp></dd>
	<dt>[[Exec Command]]</dt>
	<dd>Run external command without waiting for the result <samp>eg. [[Exec python my_python_script.py]]</samp></dd>
	<dt>[[ExecReturn Command]]</dt>
	<dd>Run external command and send the result to RAMPS <samp>eg. [[ExecReturn python my_python_script.py]]</samp></dd>
</dl>
<br>
<h4>Hardware Keywords</h4>
<dl class="dl-horizontal small">
	<dt>[[GPIOWaitForLow]]</dt>
	<dd>Wait for <kbd>"wait pin"</kbd> GPIO to be LOW</dd>
	<dt>[[Projector Command]]</dt>
	<dd>Send any command to the projector <samp>eg. [[Projector \x01\x02\x03 On]]</samp></dd>
	<dt>[[GPIOHigh GPIO]]</dt>
	<dd>Makes any GPIO HIGH <samp>eg. [[GPIOHigh 12]]</samp></dd>
	<dt>[[GPIOLow GPIO]]</dt>
	<dd>Makes any GPIO Low</dd>
</dl>

<br>

<h4>Syncronizing Movements</h4>
nanoDLP does not have knowledge of how much time it would take to finish a movement. There are a couple of ways to solve this problem.<br>
<br>
<h5>1. Using [[Delay Seconds]] keyword</h5>
It is possible to put delay after each movement. It is the most widely used method.
<pre>
G1 Z1.1
[[Delay 1.5]]
</pre>
<br>

<h5>2. Using [[GPIOWaitForLow]] keyword</h5>
To syncronize movements nanoDLP waits for pin to be LOW. At the start of movement, controllers / drivers must make this pin HIGH and at the end of movement make it LOW. Maximum delay for detection is 1ms.
<pre>
G1 Z1.1
[[GPIOWaitForLow]]
</pre>
<br>

<h5>3. Using [[WaitForDoneMessage]] keyword</h5>
By using the patched <a href="https://github.com/kitprinter3d/grbl/tree/master/grbl-solidray">grbl</a> / <a href="https://github.com/mUVe3D/Marlin-mUVe1DLP-Running">marlin</a> firmwares you can achieve sync movements. After seeing this keyword nanoDLP will wait for <kbd>Z_move_comp</kbd> response from RAMPS.
<pre>
G1 Z1.1
[[WaitForDoneMessage]]
</pre>
<br>

<h5>4. Using [[ResponseCheck ExpectedOK BufferSize]] keyword</h5>
If the firmware you are using on the controller board send ok response after execution of each command, you can use this command to syncronize movements.
<pre>
G1 X1.1
[[ResponseCheck 1 1]]
</pre>
<br>		

<br>
<h4>Crash Recovery</h4>
Using the right settings is the key to crash recovery and to benefit from nanoDLP in full potential. A way to do this is to delegate positioning to nanoDLP.<br>
Follow the sample codes below to understand how to delegate positioning to nanoDLP. By doing so in addition to crash recovery, printer stop and other functions also will start working.<br>
<br>
Start of Print
<pre>G90 ; Put positioning in absolute mode
G28 ; Homing
[[WaitForDoneMessage]] ; Wait until movement is completed, it requires firmwares to get patched for Z_move_comp, if you do not want to use patched firmware you can use [[Delay n.n]] instead
[[PositionSet 0]] ; Set current position on nanodlp so it could be recovered in case of failure</pre>
<br>
Before Layer
<pre>G1 Z[[LayerPosition]] ; Move to layer position
[[WaitForDoneMessage]] ; Wait for the movement to get finished
[[PositionSet [[LayerPosition]]]] ; Save layer position as the current position</pre>
<br>
After Layer
<pre>G1 Z{[[LayerPosition]]+[[ZLiftDistance]]} ; Lift to wait position
[[WaitForDoneMessage]] ; Wait for the movement to get finished
[[PositionChange [[ZLiftDistance]]]] ; Again update position</pre>
<br>
Resume Print
<pre>G90 ; Put positioning in absolute mode
G92 Z[[CurrentPosition]] Y0 X0 ; System crashed so we need to recover current position from nanodlp and set it on RAMP
G1 Z[[LayerPosition]] ; Move to layer position
...</pre>
